Expression syntax
Several features let you evaluate and manipulate variables using a compact expression language. The same syntax is used in all of the following places:
#if/#elseifconditions in prompt expansion – see Prompt conditions.- Logical condition node conditions, and logical statements in conversation node transitions / global node conditions in Flows – see Logical condition node and Conversation node transitions.
- Calculate node statements in Flows – see Calculate node.
- Derived variables – assigning the result of an expression to a variable using the
((expression))syntax (see Agent variables).
The expression syntax is Python-like – if you are familiar with basic Python expressions, it will feel natural. This page describes the operators and functions that are available (only a restricted, safe subset is supported, as noted below).
Variable names vs. variable expansion
Inside an expression, refer to a variable by its name, “as is” – do not wrap it in curly brackets. Curly brackets ({var} / {{var}}) are only used when expanding a variable into surrounding text.
Enclose string values that you compare against in quotes, for example status == "active".
Safety
Expressions are evaluated in a restricted, sandboxed environment. Only the operators and functions listed on this page are available – arbitrary code, imports, loops, and unlisted functions (for example eval, any, isinstance) are rejected and produce an evaluation error.
Values and types
You can use the following kinds of values in an expression:
| Value | Examples |
|---|---|
| Variable reference | age, customer_name, visits_count |
| String literal | "active", "+1800..." |
| Number | 18, 3.14 |
| Boolean | True, False |
| List | ("John", "Jack", "Jonathan"), [1, 2, 3] |
A variable keeps the type it was assigned. Numbers and booleans written literally are treated as numeric / boolean. When a variable holds text (for example a value coming from entity extraction or from a NAME = VALUE configuration), use the type-casting functions to convert it before a numeric or boolean comparison – for example int(age) > 18.
Comparison operators
| Operator | Meaning |
|---|---|
==
|
equal |
!=
|
not equal |
< <= |
less than / less than or equal |
> >= |
greater than / greater than or equal |
age >= 18
status == "active"
Comparisons can also be chained, for example 0 < age < 120 or "08:00:00" <= current_time < "18:00:00".
You can also test a string variable for “has a value” by specifying its name alone (an empty string is treated as false):
{{#if customer_name}}
Logical operators
Use and, or, and not to combine conditions:
is_admin and age > 18
not is_guest
Arithmetic operators
Mainly used in Calculate node statements and ((...)) derivations:
| Operator | Meaning |
|---|---|
+
|
addition (also string concatenation) |
-
|
subtraction |
*
|
multiplication |
/
|
division |
//
|
integer division |
%
|
remainder (modulo) |
**
|
exponentiation |
total_participants = adults_num + children_num
remaining = total - used
Membership (array) operators
Use in and not in to test whether a value is contained in a list, or whether a substring appears in a string. Specify lists as a comma-separated set of values enclosed in brackets.
person_name in ("John", "Jack", "Jonathan")
"please leave a message" in user_utterance
Conditional (ternary) expression
Use value_if_true if condition else value_if_false to choose between two values in a single expression. This is especially useful in Calculate node statements and ((...)) derivations:
greeting = "Hi" if informal else "Good day"
Indexing and slicing
You can index and slice string (and list) values using square brackets, including negative indexes:
caller[0]
caller[1:]
caller[-1]
Brackets
Use brackets to group sub-expressions and to write multi-line conditions:
{{#if (person_name == "John" or
person_name == "Jack" or
person_name == "Jonathan")}}
Say "Hello, Mr. J!"
{{/if}}
String methods
The following methods are available on string values:
| Method | Description |
|---|---|
.lower()
|
convert to lowercase |
.upper()
|
convert to uppercase |
.strip()
|
remove leading and trailing whitespace |
.lstrip()
|
remove leading whitespace |
.rstrip()
|
remove trailing whitespace |
.startswith(prefix)
|
True if the value starts with prefix |
.endswith(suffix)
|
True if the value ends with suffix |
status.lower() == "active"
person_name.startswith("J")
Type-casting functions
Convert a value to a specific type. Each function accepts an optional second argument that is returned when the value is missing or cannot be converted; if you omit it, the default shown below is used.
| Function | Converts to | Default on failure / missing |
|---|---|---|
int(value[, default])
|
integer | -1
|
float(value[, default])
|
float | -1.0
|
bool(value[, default])
|
boolean | False
|
str(value[, default])
|
string | "" (empty string) |
int(age) > 18
float(score, 0) >= 0.5
str(age) == "18"
For bool(), the strings "true", "yes", "y", and "1" (case-insensitive) convert to True; any other string converts to False. Numbers convert to False only when they are 0.
len()
len(value[, default]) returns the number of items in a string, list, tuple, dictionary, or set. For any other type (or a missing variable) it returns the default, which is 0 unless you specify otherwise.
len(customer_name) > 0
len(items) == 3
digits()
digits(value) returns a string containing only the digit characters found in value – every space, letter, and punctuation mark is removed. This is handy for normalizing a number the user spoke or typed with extra separators, for example turning my number is 1 2 3 into 123 before you compare, count, or validate it.
digits(user_response) == "123"
len(digits(phone_number)) == 10
A non-negative whole number is accepted too and its digits are returned as text. Anything with no digits to extract yields an empty string.
Validation functions
These helpers validate common identifier formats and return a boolean. Each accepts the value as a string or a number; spaces and dashes in string input are ignored.
| Function | Description |
|---|---|
verify_credit_card(value)
|
True if value is a valid credit-card number (13–19 digits passing the Luhn check). |
verify_israeli_id(value)
|
True if value is a valid Israeli ID number (teudat zehut) – 9 digits with a valid check digit. |
{{#if verify_israeli_id(id)}} ID is valid {{#else}} Please repeat your ID {{/if}}
Undefined variables
If an expression references a variable that has not been set, that variable evaluates to a special “undefined” value:
- It is treated as false in a boolean context.
- Any comparison against it evaluates to false.
- No error is produced.
This means you can safely reference variables that may not yet exist – for example {{#if order_total > 100}} simply yields false while order_total is still undefined, rather than failing.
Using time variables in conditions
How you reference a time variable (such as current_time) in a condition depends on where the condition runs:
-
Prompt
#if/#elseifconditions. Time variables are expanded into text before the condition is evaluated, so you reference them with curly brackets and wrap the result in quotes –"{current_time}". See Use of time variables in conditions.{{#if "{current_time}" < "18:00:00"}} -
Logical condition nodes and conversation-node logical transitions. These evaluate the expression directly against the flow variables – there is no text-expansion step – so reference the time variable by its name, “as is”, exactly like any other variable (do not use curly brackets). Enclose the value you compare against in quotes:
"08:00:00" <= current_time < "18:00:00"current_timeis formatted asHH:MM:SS(24-hour, zero-padded), so a plain string comparison matches chronological order. For time-based routing it is often simpler to compare the numeric components (current_hour,current_minute, …) that Flows also expose – see Dynamic variables.